/************************************************************************/
/*Copyright (c) James Zhao 2007,2008
/*This file is part of AdminOverlay.
/*AdminOverlay is free software: you can redistribute it and/or modify
/*it under the terms of the GNU General Public License as published by
/*the Free Software Foundation, either version 3 of the License, or
/*(at your option) any later version.
/*
/*AdminOverlay is distributed in the hope that it will be useful,
/*but WITHOUT ANY WARRANTY; without even the implied warranty of
/*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/*GNU General Public License for more details.
/*
/*You should have received a copy of the GNU General Public License
/*along with AdminOverlay.  If not, see <http://www.gnu.org/licenses/>.                                                                     */
/*************************************************************************/
#include "XMLRPCUtils.h"
#include "QtXml/QtXml"

const QString xmlBegin = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodCall><methodName>";
const QString xmlEnd = "</methodName><params/></methodCall>";

const QString httpHeaderBegin = "POST /RPC2 HTTP/1.1\r\nContent-Type: text/xml\r\nContent-Length: ";
const QString httpHeaderEnd = "\r\n\r\n";

QString XMLRPCUtils::getRPCXML(QString cmd)
{
	return xmlBegin + cmd + xmlEnd;
}
QString XMLRPCUtils::getHttpHeader(QString xmlCommand)
{
	return httpHeaderBegin + QString::number(xmlCommand.length()) + httpHeaderEnd;
}
QString XMLRPCUtils::hashString(QString str)
{
	QCryptographicHash hasher(QCryptographicHash::Md5);
	hasher.addData(str.toAscii());
	return QString(hasher.result().toHex());
}
void XMLRPCUtils::postCommand(QTcpSocket *tc, QString cmd)
{
	QString xmlCommand = getRPCXML(cmd);
	QString httpRequest = getHttpHeader(xmlCommand) + xmlCommand;
	tc->write(httpRequest.toAscii());
}
QString XMLRPCUtils::generateAuthenticationResponse(QString challenge, QString password)
{
	QString composed = challenge + ":" + password;
	return hashString(composed);
}
bool XMLRPCUtils::authenticate(QTcpSocket *tc, QString password)
{
	postCommand(tc, "challenge");
	QString challenge = getResult(tc);
	postCommand(tc, "authenticate " +
		generateAuthenticationResponse(challenge, password));
	QString result = getResult(tc);
	if (result == "authorized")
	{
		return true;
	}
	else
	{
		return false;
	}
}


QString XMLRPCUtils::getResult(QTcpSocket *tc)
{
	if(tc->waitForReadyRead(10000) == false)
	{
		throw QString("GetResult Failed: No read data");
	}
	int bytesToRead;
	QString content = tc->readLine();
	while (content.contains("Content-Length") == false)
	{
		content = tc->readLine();
	}
	QString lengthString = content;
	QStringList splitLengthString = lengthString.split(':');
	bytesToRead = splitLengthString[1].toInt();
	content= tc->readLine().trimmed();
	while (content != "")
	{
		content = tc->readLine().trimmed();
	}
	QByteArray xmlString = tc->read(bytesToRead);
	//QString xmlString = tc->readLine();
	return extractResponse(xmlString);


}
//sample xml for extractResponse
/*
"<?xml version=\"1.0\"?>
<methodResponse>
<params><param><value>

<string>52205.159461</string>

</value></param></params>
</methodResponse>"
*/
QString XMLRPCUtils::extractResponse( QString xmlString )
{
	QDomDocument xmlDoc;
	xmlDoc.setContent(xmlString);
	QDomElement root = xmlDoc.documentElement();
	QString text = root.text();
	if (text == "")
	{
		//there's no result
		return "";
	}
	else
	{
		//remove the $ signs
		QRegExp regex("\\$.");
		text = text.replace(regex, "");
		text = removeDumpToDisk(text);
		text = removeEmptyBracketPairs(text);
		return text.trimmed();
	}
	return NULL;
}
QString XMLRPCUtils::removeEmptyBracketPairs(QString val)
{
	return val.replace("[]", "");
}
QString XMLRPCUtils::removeDumpToDisk(QString val)
{
	return val.replace("[DUMPTODISK]", "");
}

Player* XMLRPCUtils::buildPlayer( QString playerString )
{
	Player *player = new Player();
	if (playerString == NULL || playerString == "")
		throw QString("playerString is null or blank");
	QStringList kvs = playerString.split(QRegExp("[\\s:]"),	QString::SkipEmptyParts);
	//if the player is still connecting
	if (kvs[1].trimmed() == "id")
	{
		player->State = PlayerState_Connecting;
		return player;
	}
	else
	{
		player->State = PlayerState_InGame;
		player->Name = kvs[1].trimmed().utf16();
		player->ID = kvs[3].toInt();
		player->IP = kvs[5].utf16();
		player->Port = kvs[6].toInt();
		player->Ping = kvs[8].toInt();
		player->ProfileID = kvs[12].trimmed().utf16();
		return player;
	}
}